--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
tests/e2e/helpers.js 5fa79d363bcbbb6c8fa7d6f26ee429eaa099a7ab (5fa79d36) Text, 5.71 KB
Tff7b72const Te6edf3crypto Tff7b72= Te6edf3requireTb4b4b4(Ta5d6ff"crypto"Tb4b4b4)Tb4b4b4;
Tff7b72const Tb4b4b4{ Te6edf3expect Tb4b4b4} Tff7b72= Te6edf3requireTb4b4b4(Ta5d6ff"@playwright/test"Tb4b4b4)Tb4b4b4;
Tff7b72const Te6edf3E2E_BACKEND_PORT Tff7b72= Te6edf3processTb4b4b4.Te6edf3envTb4b4b4.Te6edf3E2E_BACKEND_PORT Tff7b72|| Ta5d6ff"18079"Tb4b4b4;
Tff7b72const Te6edf3E2E_BACKEND_ORIGIN Tff7b72= Ta5d6ff`Ta5d6ffhttp://127.0.0.1:Tffd700${Te6edf3E2E_BACKEND_PORTTffd700}Ta5d6ff`Tb4b4b4;
Tff7b72const Te6edf3E2E_SCROLL_PEER_HASH Tff7b72= Ta5d6ff`Ta5d6ffe2e0Tffd700${Ta5d6ff"0"Tb4b4b4.Te6edf3repeatTb4b4b4(T79c0ff28Tb4b4b4)Tffd700}Ta5d6ff`Tb4b4b4;
Tff7b72const Te6edf3E2E_SCROLL_ALT_PEER_HASH Tff7b72= Ta5d6ff`Ta5d6ffe2e1Tffd700${Ta5d6ff"0"Tb4b4b4.Te6edf3repeatTb4b4b4(T79c0ff28Tb4b4b4)Tffd700}Ta5d6ff`Tb4b4b4;
Tff7b72function Te6edf3buildE2eLxmfRowTb4b4b4(Tb4b4b4{ Te6edf3peerHashTb4b4b4, Te6edf3localHashTb4b4b4, Te6edf3indexTb4b4b4, Te6edf3totalTb4b4b4, Te6edf3inbound Tb4b4b4}Tb4b4b4) Tb4b4b4{
Tff7b72const Te6edf3hash Tff7b72= Te6edf3cryptoTb4b4b4.Te6edf3randomBytesTb4b4b4(T79c0ff16Tb4b4b4)Tb4b4b4.Te6edf3toStringTb4b4b4(Ta5d6ff"hex"Tb4b4b4)Tb4b4b4;
Tff7b72const Te6edf3baseTs Tff7b72= Tffa657MathTb4b4b4.Te6edf3floorTb4b4b4(Tffa657DateTb4b4b4.Te6edf3nowTb4b4b4(Tb4b4b4) Tff7b72/ T79c0ff1000Tb4b4b4) Tff7b72- Te6edf3totalTb4b4b4;
Tff7b72return Tb4b4b4{
Te6edf3hashTb4b4b4,
Te6edf3source_hashTff7b72: Te6edf3inbound Tff7b72? Te6edf3peerHash Tff7b72: Te6edf3localHashTb4b4b4,
Te6edf3destination_hashTff7b72: Te6edf3inbound Tff7b72? Te6edf3localHash Tff7b72: Te6edf3peerHashTb4b4b4,
Te6edf3peer_hashTff7b72: Te6edf3peerHashTb4b4b4,
Te6edf3stateTff7b72: Ta5d6ff"delivered"Tb4b4b4,
Te6edf3progressTff7b72: T79c0ff1.0Tb4b4b4,
Te6edf3is_incomingTff7b72: Te6edf3inbound Tff7b72? T79c0ff1 Tff7b72: T79c0ff0Tb4b4b4,
Te6edf3methodTff7b72: Ta5d6ff"direct"Tb4b4b4,
Te6edf3delivery_attemptsTff7b72: T79c0ff1Tb4b4b4,
Te6edf3next_delivery_attempt_atTff7b72: Tff7b72nullTb4b4b4,
Te6edf3titleTff7b72: Ta5d6ff""Tb4b4b4,
Te6edf3contentTff7b72: Ta5d6ff`Ta5d6ffE2E scroll seed Tffd700${Tffa657StringTb4b4b4(Te6edf3indexTb4b4b4)Tb4b4b4.Te6edf3padStartTb4b4b4(T79c0ff3Tb4b4b4, Ta5d6ff"0"Tb4b4b4)Tffd700}Ta5d6ff Tffd700${Ta5d6ff"x"Tb4b4b4.Te6edf3repeatTb4b4b4(T79c0ff64Tb4b4b4)Tffd700}Ta5d6ff`Tb4b4b4,
Te6edf3fieldsTff7b72: Ta5d6ff"{}"Tb4b4b4,
Te6edf3timestampTff7b72: Te6edf3baseTs Tff7b72+ Te6edf3indexTb4b4b4,
Te6edf3rssiTff7b72: Tff7b72nullTb4b4b4,
Te6edf3snrTff7b72: Tff7b72nullTb4b4b4,
Te6edf3qualityTff7b72: Tff7b72nullTb4b4b4,
Te6edf3is_spamTff7b72: T79c0ff0Tb4b4b4,
Te6edf3reply_to_hashTff7b72: Tff7b72nullTb4b4b4,
Te6edf3attachments_strippedTff7b72: T79c0ff0Tb4b4b4,
Tb4b4b4}Tb4b4b4;
Tb4b4b4}
T8b949e/**
* @param {import('@playwright/test').APIRequestContext} request
* @returns {Promise<string>}
*/
Tff7b72async Tff7b72function Te6edf3getE2eLocalLxmfHashTb4b4b4(Te6edf3requestTb4b4b4) Tb4b4b4{
Tff7b72const Te6edf3cfgRes Tff7b72= Tff7b72await Te6edf3requestTb4b4b4.Te6edf3getTb4b4b4(Ta5d6ff`Tffd700${Te6edf3E2E_BACKEND_ORIGINTffd700}Ta5d6ff/api/v1/configTa5d6ff`Tb4b4b4)Tb4b4b4;
Te6edf3expectTb4b4b4(Te6edf3cfgResTb4b4b4.Te6edf3okTb4b4b4(Tb4b4b4)Tb4b4b4)Tb4b4b4.Te6edf3toBeTruthyTb4b4b4(Tb4b4b4)Tb4b4b4;
Tff7b72const Te6edf3cfgBody Tff7b72= Tff7b72await Te6edf3cfgResTb4b4b4.Te6edf3jsonTb4b4b4(Tb4b4b4)Tb4b4b4;
Tff7b72const Te6edf3localHash Tff7b72= Te6edf3cfgBodyTb4b4b4.Te6edf3configTff7b72?Tb4b4b4.Te6edf3lxmf_address_hashTb4b4b4;
Te6edf3expectTb4b4b4(Te6edf3localHash Tff7b72&& Tffa657StringTb4b4b4(Te6edf3localHashTb4b4b4)Tb4b4b4.Te6edf3length Tff7b72=== T79c0ff32Tb4b4b4)Tb4b4b4.Te6edf3toBeTruthyTb4b4b4(Tb4b4b4)Tb4b4b4;
Tff7b72return Te6edf3localHashTb4b4b4;
Tb4b4b4}
T8b949e/**
* Inserts LXMF rows via maintenance import so the messages UI has a long thread for scroll tests.
* @param {import('@playwright/test').APIRequestContext} request
* @param {{ messageCount?: number }} [opts]
* @returns {Promise<{ peerHash: string, localHash: string }>}
*/
Tff7b72async Tff7b72function Te6edf3seedE2eLongConversationThreadTb4b4b4(Te6edf3requestTb4b4b4, Te6edf3opts Tff7b72= Tb4b4b4{Tb4b4b4}Tb4b4b4) Tb4b4b4{
Tff7b72const Te6edf3messageCount Tff7b72= Te6edf3optsTb4b4b4.Te6edf3messageCount Tff7b72?? T79c0ff45Tb4b4b4;
Tff7b72const Te6edf3localHash Tff7b72= Tff7b72await Te6edf3getE2eLocalLxmfHashTb4b4b4(Te6edf3requestTb4b4b4)Tb4b4b4;
Tff7b72const Te6edf3peerHash Tff7b72= Te6edf3E2E_SCROLL_PEER_HASHTb4b4b4;
Tff7b72const Te6edf3messages Tff7b72= Tb4b4b4[Tb4b4b4]Tb4b4b4;
Tff7b72for Tb4b4b4(Tff7b72let Te6edf3i Tff7b72= T79c0ff0Tb4b4b4; Te6edf3i Tff7b72< Te6edf3messageCountTb4b4b4; Te6edf3iTff7b72++Tb4b4b4) Tb4b4b4{
Te6edf3messagesTb4b4b4.Te6edf3pushTb4b4b4(
Te6edf3buildE2eLxmfRowTb4b4b4(Tb4b4b4{
Te6edf3peerHashTb4b4b4,
Te6edf3localHashTb4b4b4,
Te6edf3indexTff7b72: Te6edf3iTb4b4b4,
Te6edf3totalTff7b72: Te6edf3messageCountTb4b4b4,
Te6edf3inboundTff7b72: Te6edf3i Tff7b72% T79c0ff2 Tff7b72=== T79c0ff0Tb4b4b4,
Tb4b4b4}Tb4b4b4)
Tb4b4b4)Tb4b4b4;
Tb4b4b4}
Tff7b72const Te6edf3imp Tff7b72= Tff7b72await Te6edf3requestTb4b4b4.Te6edf3postTb4b4b4(Ta5d6ff`Tffd700${Te6edf3E2E_BACKEND_ORIGINTffd700}Ta5d6ff/api/v1/maintenance/messages/importTa5d6ff`Tb4b4b4, Tb4b4b4{
Te6edf3dataTff7b72: Tb4b4b4{ Te6edf3messages Tb4b4b4}Tb4b4b4,
Tb4b4b4}Tb4b4b4)Tb4b4b4;
Te6edf3expectTb4b4b4(Te6edf3impTb4b4b4.Te6edf3okTb4b4b4(Tb4b4b4)Tb4b4b4)Tb4b4b4.Te6edf3toBeTruthyTb4b4b4(Tb4b4b4)Tb4b4b4;
Tff7b72return Tb4b4b4{ Te6edf3peerHashTb4b4b4, Te6edf3localHash Tb4b4b4}Tb4b4b4;
Tb4b4b4}
T8b949e/**
* Second conversation for tests that switch between a long and a short thread.
* @param {import('@playwright/test').APIRequestContext} request
* @param {{ messageCount?: number }} [opts]
*/
Tff7b72async Tff7b72function Te6edf3seedE2eAltShortConversationThreadTb4b4b4(Te6edf3requestTb4b4b4, Te6edf3opts Tff7b72= Tb4b4b4{Tb4b4b4}Tb4b4b4) Tb4b4b4{
Tff7b72const Te6edf3messageCount Tff7b72= Te6edf3optsTb4b4b4.Te6edf3messageCount Tff7b72?? T79c0ff12Tb4b4b4;
Tff7b72const Te6edf3localHash Tff7b72= Tff7b72await Te6edf3getE2eLocalLxmfHashTb4b4b4(Te6edf3requestTb4b4b4)Tb4b4b4;
Tff7b72const Te6edf3peerHash Tff7b72= Te6edf3E2E_SCROLL_ALT_PEER_HASHTb4b4b4;
Tff7b72const Te6edf3messages Tff7b72= Tb4b4b4[Tb4b4b4]Tb4b4b4;
Tff7b72for Tb4b4b4(Tff7b72let Te6edf3i Tff7b72= T79c0ff0Tb4b4b4; Te6edf3i Tff7b72< Te6edf3messageCountTb4b4b4; Te6edf3iTff7b72++Tb4b4b4) Tb4b4b4{
Tff7b72const Te6edf3row Tff7b72= Te6edf3buildE2eLxmfRowTb4b4b4(Tb4b4b4{
Te6edf3peerHashTb4b4b4,
Te6edf3localHashTb4b4b4,
Te6edf3indexTff7b72: Te6edf3iTb4b4b4,
Te6edf3totalTff7b72: Te6edf3messageCountTb4b4b4,
Te6edf3inboundTff7b72: Te6edf3i Tff7b72% T79c0ff2 Tff7b72=== T79c0ff0Tb4b4b4,
Tb4b4b4}Tb4b4b4)Tb4b4b4;
Te6edf3rowTb4b4b4.Te6edf3content Tff7b72= Ta5d6ff`Ta5d6ffE2E alt short Tffd700${Tffa657StringTb4b4b4(Te6edf3iTb4b4b4)Tb4b4b4.Te6edf3padStartTb4b4b4(T79c0ff3Tb4b4b4, Ta5d6ff"0"Tb4b4b4)Tffd700}Ta5d6ff Tffd700${Ta5d6ff"x"Tb4b4b4.Te6edf3repeatTb4b4b4(T79c0ff48Tb4b4b4)Tffd700}Ta5d6ff`Tb4b4b4;
Te6edf3messagesTb4b4b4.Te6edf3pushTb4b4b4(Te6edf3rowTb4b4b4)Tb4b4b4;
Tb4b4b4}
Tff7b72const Te6edf3imp Tff7b72= Tff7b72await Te6edf3requestTb4b4b4.Te6edf3postTb4b4b4(Ta5d6ff`Tffd700${Te6edf3E2E_BACKEND_ORIGINTffd700}Ta5d6ff/api/v1/maintenance/messages/importTa5d6ff`Tb4b4b4, Tb4b4b4{
Te6edf3dataTff7b72: Tb4b4b4{ Te6edf3messages Tb4b4b4}Tb4b4b4,
Tb4b4b4}Tb4b4b4)Tb4b4b4;
Te6edf3expectTb4b4b4(Te6edf3impTb4b4b4.Te6edf3okTb4b4b4(Tb4b4b4)Tb4b4b4)Tb4b4b4.Te6edf3toBeTruthyTb4b4b4(Tb4b4b4)Tb4b4b4;
Tff7b72return Tb4b4b4{ Te6edf3peerHashTb4b4b4, Te6edf3localHash Tb4b4b4}Tb4b4b4;
Tb4b4b4}
Tff7b72const Te6edf3PALETTE_PLACEHOLDER Tff7b72= Ta5d6ff/Search commands,\s*(routes|navigate),\s*or peers\.{0,3}/iTb4b4b4;
T8b949e/**
* Marks tutorial and changelog as seen on the E2E backend so first-load modals
* (v-overlay scrim) do not block pointer clicks on the shell.
*/
Tff7b72async Tff7b72function Te6edf3prepareE2eSessionTb4b4b4(Te6edf3requestTb4b4b4) Tb4b4b4{
Tff7b72const Te6edf3tutorial Tff7b72= Tff7b72await Te6edf3requestTb4b4b4.Te6edf3postTb4b4b4(Ta5d6ff`Tffd700${Te6edf3E2E_BACKEND_ORIGINTffd700}Ta5d6ff/api/v1/app/tutorial/seenTa5d6ff`Tb4b4b4)Tb4b4b4;
Te6edf3expectTb4b4b4(Te6edf3tutorialTb4b4b4.Te6edf3okTb4b4b4(Tb4b4b4)Tb4b4b4)Tb4b4b4.Te6edf3toBeTruthyTb4b4b4(Tb4b4b4)Tb4b4b4;
Tff7b72const Te6edf3changelog Tff7b72= Tff7b72await Te6edf3requestTb4b4b4.Te6edf3postTb4b4b4(Ta5d6ff`Tffd700${Te6edf3E2E_BACKEND_ORIGINTffd700}Ta5d6ff/api/v1/app/changelog/seenTa5d6ff`Tb4b4b4, Tb4b4b4{
Te6edf3dataTff7b72: Tb4b4b4{ Te6edf3versionTff7b72: Ta5d6ff"999.999.999" Tb4b4b4}Tb4b4b4,
Tb4b4b4}Tb4b4b4)Tb4b4b4;
Te6edf3expectTb4b4b4(Te6edf3changelogTb4b4b4.Te6edf3okTb4b4b4(Tb4b4b4)Tb4b4b4)Tb4b4b4.Te6edf3toBeTruthyTb4b4b4(Tb4b4b4)Tb4b4b4;
Tb4b4b4}
Tff7b72async Tff7b72function Te6edf3openCommandPaletteTb4b4b4(Te6edf3pageTb4b4b4) Tb4b4b4{
Tff7b72await Te6edf3pageTb4b4b4.Te6edf3waitForLoadStateTb4b4b4(Ta5d6ff"domcontentloaded"Tb4b4b4)Tb4b4b4;
Tff7b72await Te6edf3pageTb4b4b4.Te6edf3keyboardTb4b4b4.Te6edf3pressTb4b4b4(Ta5d6ff"Control+K"Tb4b4b4)Tb4b4b4;
Tff7b72let Te6edf3input Tff7b72= Te6edf3pageTb4b4b4.Te6edf3getByPlaceholderTb4b4b4(Te6edf3PALETTE_PLACEHOLDERTb4b4b4)Tb4b4b4;
Tff7b72if Tb4b4b4(Tb4b4b4(Tff7b72await Te6edf3inputTb4b4b4.Te6edf3countTb4b4b4(Tb4b4b4)Tb4b4b4) Tff7b72=== T79c0ff0Tb4b4b4) Tb4b4b4{
Tff7b72await Te6edf3pageTb4b4b4.Te6edf3evaluateTb4b4b4(Tb4b4b4(Tb4b4b4) Tb4b4b4=> Tb4b4b4{
Tff7b72const Te6edf3ctrlK Tff7b72= Tff7b72new Te6edf3KeyboardEventTb4b4b4(Ta5d6ff"keydown"Tb4b4b4, Tb4b4b4{
Te6edf3keyTff7b72: Ta5d6ff"k"Tb4b4b4,
Te6edf3codeTff7b72: Ta5d6ff"KeyK"Tb4b4b4,
Te6edf3ctrlKeyTff7b72: Tff7b72trueTb4b4b4,
Te6edf3bubblesTff7b72: Tff7b72trueTb4b4b4,
Te6edf3cancelableTff7b72: Tff7b72trueTb4b4b4,
Tb4b4b4}Tb4b4b4)Tb4b4b4;
Tffa657windowTb4b4b4.Te6edf3dispatchEventTb4b4b4(Te6edf3ctrlKTb4b4b4)Tb4b4b4;
Tffa657documentTb4b4b4.Te6edf3dispatchEventTb4b4b4(Te6edf3ctrlKTb4b4b4)Tb4b4b4;
Tb4b4b4}Tb4b4b4)Tb4b4b4;
Te6edf3input Tff7b72= Te6edf3pageTb4b4b4.Te6edf3getByPlaceholderTb4b4b4(Te6edf3PALETTE_PLACEHOLDERTb4b4b4)Tb4b4b4;
Tb4b4b4}
Tff7b72await Te6edf3expectTb4b4b4(Te6edf3inputTb4b4b4)Tb4b4b4.Te6edf3toBeVisibleTb4b4b4(Tb4b4b4{ Te6edf3timeoutTff7b72: T79c0ff15000 Tb4b4b4}Tb4b4b4)Tb4b4b4;
Tb4b4b4}
Tff7b72async Tff7b72function Te6edf3dismissMapOnboardingTooltipTb4b4b4(Te6edf3pageTb4b4b4) Tb4b4b4{
Tff7b72const Te6edf3onboardingBackdrop Tff7b72= Te6edf3pageTb4b4b4.Te6edf3locatorTb4b4b4(
Ta5d6ff"div.fixed.inset-0.z-\\[100\\].pointer-events-none > div.absolute.inset-0.bg-black\\/50.pointer-events-auto"
Tb4b4b4)Tb4b4b4;
Tff7b72if Tb4b4b4(Tb4b4b4(Tff7b72await Te6edf3onboardingBackdropTb4b4b4.Te6edf3countTb4b4b4(Tb4b4b4)Tb4b4b4) Tff7b72> T79c0ff0Tb4b4b4) Tb4b4b4{
Tff7b72await Te6edf3onboardingBackdropTb4b4b4.Te6edf3clickTb4b4b4(Tb4b4b4{ Te6edf3timeoutTff7b72: T79c0ff5000 Tb4b4b4}Tb4b4b4)Tb4b4b4;
Tff7b72await Te6edf3expectTb4b4b4(Te6edf3onboardingBackdropTb4b4b4)Tb4b4b4.Te6edf3toBeHiddenTb4b4b4(Tb4b4b4{ Te6edf3timeoutTff7b72: T79c0ff10000 Tb4b4b4}Tb4b4b4)Tb4b4b4;
Tb4b4b4}
Tb4b4b4}
Te6edf3moduleTb4b4b4.Te6edf3exports Tff7b72= Tb4b4b4{
Te6edf3E2E_BACKEND_ORIGINTb4b4b4,
Te6edf3E2E_SCROLL_PEER_HASHTb4b4b4,
Te6edf3E2E_SCROLL_ALT_PEER_HASHTb4b4b4,
Te6edf3PALETTE_PLACEHOLDERTb4b4b4,
Te6edf3dismissMapOnboardingTooltipTb4b4b4,
Te6edf3openCommandPaletteTb4b4b4,
Te6edf3prepareE2eSessionTb4b4b4,
Te6edf3getE2eLocalLxmfHashTb4b4b4,
Te6edf3seedE2eLongConversationThreadTb4b4b4,
Te6edf3seedE2eAltShortConversationThreadTb4b4b4,
Tb4b4b4}Tb4b4b4;
──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────